/*
 * Mandelbrot.h
 *
 *  Created on: 03-08-2011
 *      Author: rego
 */

#ifndef MANDELBROT_H_
#define MANDELBROT_H_

template <typename T>
class Mandelbrot {

	int **values;

	T zWidth;
	T zHeight;
	T re, im;
	T step;

	int maxI;
	int MAX_I;

	bool refresh;

	static const float ZOOM_FACTOR = 1.5;
	static const float MOVE_FACTOR = 0.5;

public:

	static const int picWidth = 640;
	static const int picHeight = 480;
	static int grid;

	Mandelbrot<T>(): maxI(0), MAX_I(20), refresh(true) {
		values = new int*[picHeight];
		for(int i=0; i<picHeight; i++) {
			values[i] = new int[picWidth];
		}
		im = 0;
		re = -0.5;
		zWidth = 2;
		zHeight = 1.5;
		step = zWidth / picWidth;
	}

	~Mandelbrot() {
		for(int i=0; i<picHeight; i++) {
			delete [] values[i];
		}
		delete [] values;
	}

	void run() {

		if(!refresh)
			return ;

		maxI = 0;
		for(int i = 0; i < picHeight; i += grid) {
			for(int j = 0; j < picWidth; j += grid) {
				T cRe = re + step*(j-picWidth/2);
				T cIm = im + step*(i-picHeight/2);
				values[i][j] = point(cRe, cIm);
				maxI = maxI > values[i][j] ? maxI : values[i][j];
			}
			printf("*");
			fflush(stdout);
		}
		printf("\n");
		fflush(stdout);

		refresh = false;

	}

	void run(T midRe, T midIm, T width) {
		re = midRe;
		im = midIm;
		zWidth = width;
		zHeight = width*3/4;
		run();
	}

	void paintHtml() {
		for(int i = 0; i < picHeight; i += grid) {
			for(int j = 0; j < picWidth; j += grid) {

			}
//			printf("\n");
		}
	}

	void paintConsole() {
		for(int i = 0; i < picHeight; i += grid) {
			for(int j = 0; j < picWidth; j += grid) {
				printf("%c", values[i][j] == 0 ? '#' : ' ');
			}
			printf("\n");
		}
	}

	void zoomIn() {
		zWidth /= ZOOM_FACTOR;
		zHeight /= ZOOM_FACTOR;
		step = zWidth / picWidth;
		refresh = true;
	}

	void zoomOut() {
		zWidth *= ZOOM_FACTOR;
		zHeight *= ZOOM_FACTOR;
		step = zWidth / picWidth;
		refresh = true;
	}

	void move(int dx, int dy) {
		re += zWidth*dx*MOVE_FACTOR;
		im += zHeight*dy*MOVE_FACTOR;
		refresh = true;
	}

	int get(int x, int y) {
		return values[y][x];
	}

	void maxIUp() {
		MAX_I *= 2;
		refresh = true;
	}

	void maxIDown() {
		if(MAX_I > 1) {
			MAX_I /= 2;
			refresh = true;
		}
	}

	void gridUp() {
		grid *= 2;
		refresh = true;
	}

	void gridDown() {
		if(grid > 1) {
			grid /= 2;
			refresh = true;
		}
	}

private:
	int point(T cRe, T cIm) {
		T re = 0;
		T im = 0;
		for(int i = 1; i <= MAX_I; i++) {
			T temp = re*im*2 + cIm;
			re = re*re - im*im + cRe;
			im = temp;
			if(re*re + im*im > 4) {
				return i;
			}
		}
		return 0;
	}
};

template<typename T> int Mandelbrot<T>::grid = 16;

#endif /* MANDELBROT_H_ */
